home *** CD-ROM | disk | FTP | other *** search
/ SPACE 1 / SPACE - Library 1 - Volume 1.iso / program / 363 / tprolog1 / monitor.pro < prev    next >
Text File  |  1987-09-03  |  45KB  |  1,126 lines

  1. %                    TOY - the Prolog part.
  2. % (c) Copyright 1983 - Feliks Kluzniak, Stanislaw Spakowicz
  3. %           Institute of Informatics, Warsaw University.
  4. %
  5. %         ATARI ST Implementation (c) Jens J. Kilian, THD
  6. %
  7. % ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  8. % - - - - - -          INTERACTIVE DRIVER - TOP LEVEL          - - - - - -
  9. % ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  10.  
  11. ear :- nl, display('TOY Prolog listening:'), nl, tag(loop).
  12. ear :- grf_mode, halt('TOY Prolog --- end of session.').
  13.  
  14. loop :- repeat,
  15.         display(?-), read(Term, Sym_tab), exec(Term, Sym_tab), fail.
  16.  
  17. stop :- tagfail(loop).
  18. sysload(File) :- see(File), tagexit(loop).
  19.  
  20. exec('e r r', _) :- !.           % this covers variables, too
  21. exec(:-(Goals), _) :- !, once(Goals).
  22. exec(N, _) :- integer(N), !, num_clause.
  23.  
  24. % assert non-unit clauses or grammar rules entered OUTSIDE 'consult' mode
  25.  
  26. exec(:-(Head, Body), _) :- !, assimilate(:-(Head, Body)),   % cf. consult
  27.       display(ok), nl.
  28. exec(-->(Left, Right), _) :- !, assimilate(-->(Left, Right)),
  29.       display(ok), nl.
  30.  
  31. % process a list of file names
  32.  
  33. exec([H | T], _) :- !, consultall([H | T]).
  34.  
  35. % normal execution
  36.  
  37. exec(Goals, Sym_tab) :-
  38.       call(Goals), numbervars(Goals, 0, _),
  39.       printvars(Sym_tab), enough(Sym_tab), !.
  40. exec(_, _) :- display(no), nl.      % if call(Goals) fails
  41.  
  42. enough(Sym_tab) :- var(Sym_tab), !.
  43. enough(_) :- rch, skipbl, lastch(Ch), rch, not(=(Ch, ';')).
  44.  
  45. printvars(Sym_tab) :- var(Sym_tab), display(yes), nl, !.
  46. printvars(Sym_tab) :- prvars(Sym_tab).
  47.  
  48. prvars(Sym_tab) :- var(Sym_tab), !.
  49. prvars([var(NameString, Instance) | Sym_tab_tail]) :-
  50.       nl, writetext(NameString), display(' = '),
  51.       side_effects(outt(Instance, fd(_, _), q)), wch(' '),
  52.             % this is equivalent to writeq(Instance), but we avoid
  53.             % superfluous calls to numbervars - cf. write
  54.       prvars(Sym_tab_tail).
  55.  
  56. num_clause :- display('A number can''t be a clause.'), nl.
  57.  
  58. % read a program terminated by 'end.'  (NOT the only way to define user
  59. % procedures, cf. exec); consult/reconsult must be issued from the terminal,
  60. % and it returns there ( consult(user) is correct, too)
  61.  
  62. consultall([]) :- !.
  63. consultall([-(Name) | OtherNames]) :-
  64.       !, reconsult(Name), consultall(OtherNames).
  65. consultall([Name | OtherNames]) :-
  66.       !, consult(Name), consultall(OtherNames).
  67.  
  68. consult(File) :- seeing(OldF), readprog(File), see(OldF).
  69. reconsult(File) :-
  70.       redefine, seeing(OldF), readprog(File), see(OldF), redefine.
  71. readprog(user) :- !, getprog.
  72. readprog(File) :- see(File), echo, getprog, noecho, seen.
  73.  
  74. % the actual job is done by this procedure :
  75. getprog :- repeat, read(T), assimilate(T), =(T, end), !.
  76.  
  77. assimilate('e r r') :- !.     % a variable is erroneous, too
  78. assimilate( -->(Left, Right) ) :-
  79.       !, tag(transl_rule(Left, Right, Clause)), assertz(Clause).
  80. assimilate( :-(Goal) ) :- !, once(Goal).
  81. assimilate(end) :- nl, !.
  82. assimilate(N) :- integer(N), !, num_clause.
  83. % otherwise store the Clause :
  84. assimilate(Clause) :- assertz(Clause).
  85.  
  86.  
  87. % ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  88. % - - - - - -                  READ A TERM                     - - - - - -
  89. % ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  90.  
  91. read(T) :- read(T, Sym_tab).
  92. read(T, Sym_tab) :-
  93.       gettr(T_internal, Sym_tab), !, maketerm(T_internal, T).
  94. % if gettr fails, then ...
  95. read('e r r', _) :-
  96.       nl, display('+++ Bad term on input. Text skipped: '), skip, nl.
  97.  
  98. % skip to the nearest full stop not in quotes or in comment
  99. skip :- lastch(Ch), wch(Ch), skip(Ch).
  100.  
  101. skip(.)   :- rch, lastch(Ch), e_skip(Ch), !.
  102. skip('%') :- skip_comment, !, rch, skip.
  103. skip(Q)   :- isquote(Q), skip_s(Q), !, rch, skip.
  104. skip(_)   :- rch, skip.
  105.  
  106. % stop on a "layout" character
  107. e_skip(Ch) :- @=<(Ch, ' ').
  108. e_skip(Ch) :- wch(Ch), rch, skip.
  109.  
  110. skip_comment :- repeat, rch, lastch(Ch), wch(Ch), iseoln(Ch), !.
  111.  
  112. isquote('''').       isquote('"').
  113.  
  114. % skip a string
  115. skip_s(Quote) :- repeat, rch, lastch(Ch), wch(Ch), =(Ch, Quote), !.
  116.  
  117. % ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  118. % - - - - - -                    P A R S E R                   - - - - - -
  119. % ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  120. % This is an operator precedence parser for Prolog-10.  g e t t r
  121. % constructs the internal representation of a term. next, m a k e t e r m
  122. % constructs the term proper - see  r e a d. Here is an informal
  123. % description of the underlying operator precedence grammar (each "rule"
  124. % corrensponds to one clause of  r e d u c e). Sides are separated by ==>
  125. % and multiple righthand sides - by OR.
  126. %     t  ==>  variable   OR   integer   OR   string
  127. %     t  ==>  identifier
  128. %     t  ==>  identifier ( t )
  129. %     t  ==>  []   OR   {}
  130. %     t  ==>  ( t )   OR   [ t ]   OR   { t }
  131. %     t  ==>  [ t | t ]
  132. %     t  ==>  t postfix_functor
  133. %     t  ==>  t infix_functor t
  134. %     t  ==>  prefix_functor t
  135. % Sequences of terms separated by commas - in rules 3, 5, 6 - will be recognised
  136. % as comma-terms (commas are infix functors, covered by rule 8).
  137. % There are five types of operators: vns(_), id(_), ff(_, _, _),
  138. % br(_, _), bar - see the scanner. The terminal symbol dot never gets onto
  139. % the stack. The terminal symbol bottom is never returned by the scanner;
  140. % it is only used to initiate and terminate the main loop (p a r s e). The
  141. % only nonterminal symbol is t(_).
  142. % There are fives types of internal representations (Args denotes the represen-
  143. % tation of arguments - usually a comma-term):
  144. %     tr(Name, Args)       - for functor-terms,
  145. %     arg0(X)              - for X a variable, an atom, a number, or a string,
  146. %     bar(X, Y)            - for a list with front X and tail Y,
  147. %     tr1(Name, X)         - for prefix and postfix functors,
  148. %     tr2(Name, X, Y)      - for infix functors.
  149. % A Name in tr may be a bracket type. See  r e d u c e (clauses 5, 6)
  150. % and  m a k e t e r m  for details.
  151.  
  152. % - - - get the internal representation of a term
  153. gettr(X, Sym_tab) :-
  154.       gettoken(T, Sym_tab), parse([bottom], T, X, Sym_tab).
  155.  
  156. % p a r s e  takes four parameters: the current stack, the current token
  157. % from input, the variable that drifts down and brings the internal repre-
  158. % sentation to the surface, and the symbol table (used by  g e t t o k e n).
  159. parse([t(X), bottom], dot, X, _) :- !.
  160. parse(Stack, Input, X, Sym_tab) :-
  161.       topterminal(Stack, Top, Pos),
  162.       establish_precedence(Top, Input, Pos, Rel, RTop, RInput),
  163.       exch_top(Top, RTop, Stack, RStack),
  164.       step(Rel, RInput, RStack, NewStack, NewInput, Sym_tab),
  165.       parse(NewStack, NewInput, X, Sym_tab).
  166.  
  167. % the topmost terminal will be covered by at most one nonterminal
  168. % (the third parameter gives Top's position: 1 on the top, 2 covered)
  169. topterminal([t(_), Top | _], Top, 2) :- !.
  170. topterminal([Top | _], Top, 1).
  171.  
  172. % exchange the topmost terminal (applies only to disambiguated mixed functors)
  173. exch_top(Top, Top, Stack, Stack) :- !.
  174. exch_top(_, RTop, [t(X), _ | S], [t(X), RTop | S]) :- !.
  175. exch_top(_, RTop, [_ | S], [RTop | S]).
  176.  
  177. % - - - perform one step: shift (stack the current token) or reduce
  178. step(lseq, RInput, Stack, [RInput | Stack], NewInput, Sym_tab) :-
  179.       !, gettoken(NewInput, Sym_tab).
  180. step(gt, RInput, Stack, NewStack, RInput, _) :-
  181.       reduce(Stack, NewStack).
  182. % fail if reduction impossible (parse and gettr will fail, too -
  183. % this failure will be intercepted by gettr's caller)
  184.  
  185. %reduce top segment of the stack according to the underlying grammar
  186. reduce([ vns(X) | S], [t(arg0(X)) | S]).
  187. reduce([  id(I) | S], [t(arg0(I)) | S]).
  188. reduce([ br(r, '()'), t(X), br(l, '()'), id(I) | S],
  189.                                   [t(tr(I, X)) | S]).
  190. reduce([br(r, Type), br(l, Type) | S],
  191.                   [t(arg0(Type)) | S]) :- not(=(Type, '()')).
  192.                   % '[]' or '{}', see p, 2nd clause
  193. reduce([br(r, Type), t(X), br(l, Type) | S],
  194.                        [t(tr(Type, X)) | S]).
  195. reduce([br(r, '[]'), t(Y), bar, t(X), br(l, '[]') | S],
  196.                                     [t(bar(X, Y)) | S]).
  197. reduce([ff(I, Type, _), t(X) | S],
  198.                [t(tr1(I, X)) | S]) :- ismpostf(Type).
  199. reduce([t(Y), ff(I, Type, _), t(X) | S],
  200.                   [t(tr2(I, X, Y)) | S]) :- isminf(Type).
  201. reduce([t(X), ff(I, Type, _) | S],
  202.                [t(tr1(I, X)) | S]) :- ismpref(Type).
  203. % otherwise fail (cf. step)
  204.  
  205. % - - - auxiliary tests for the parser
  206. ispref(fy).       ispref(fx).
  207.  
  208. ispostf(yf).      ispostf(xf).
  209.  
  210. ismpref([TUn]) :- ispref(TUn).
  211. ismpref([_, TUn]) :- ispref(TUn).
  212.  
  213. isminf([TBin]) :- member(TBin, [yfy, xfy, yfx, xfx]).
  214. isminf([_, _]).
  215.  
  216. ismpostf([TUn]) :- ispostf(TUn).
  217. ismpostf([_, TUn]) :- ispostf(TUn).
  218.  
  219. % - - - establish precedence relation between the topmost
  220. % terminal on the stack and the current input terminal
  221. establish_precedence(Top, Input, Pos, Rel, RTop, RInput) :-
  222.       p(Top, Input, Pos, Rel0),
  223.       finalize(Rel0, Top, Input, Rel, RTop, RInput), !.
  224.  
  225. finalize(lseq, Top, Input, lseq, Top, Input).
  226. finalize(gt, Top, Input, gt, Top, Input).
  227. finalize(lseq(RTop, RInput), _, _, lseq, RTop, RInput).
  228. finalize(gt(RTop, RInput), _, _, gt, RTop, RInput).
  229.  
  230. p(id(_), br(l, '()'), 1, lseq).
  231. p(br(l, Type), br(r, Type), _, lseq).
  232. p(br(l, '[]'), bar, 2, lseq).
  233. p(bar, br(r, '[]'), 2, lseq).
  234.  
  235. p(Top, Input, 1, gt) :-
  236.       vns_id_br(Top, r), br_bar(Input, r).
  237. p(Top, ff(N, Types, P), 1, gt(Top, ff(N, RTypes, P))) :-
  238.       vns_id_br(Top, r), restrict(Types, [fx, fy], RTypes).
  239. p(Top, Input, 1, lseq) :-
  240.       br_bar(Top, l), vns_id_br(Input, l).
  241. p(Top, ff(N, Types, P), Pos, lseq(Top, ff(N, RTypes, P))) :-
  242.       br_bar(Top, l), pre_inpost(Pos, Types, RTypes).
  243. p(ff(N, Types, P), Input, Pos, gt(ff(N, RTypes, P), Input)) :-
  244.       br_bar(Input, r), post_inpre(Pos, Types, RTypes).
  245. p(ff(N, Types, P), Input, 1, lseq(ff(N, RTypes, P), Input)) :-
  246.       vns_id_br(Input, l), restrict(Types, [xf, yf], RTypes).
  247.  
  248. % functors with equal priorities
  249. p(ff(NTop, TsTop, P), ff(NInp, TsInp, P), Pos, Rel) :-
  250.       res_confl(TsTop, TsInp, Pos, RTsTop, RTsInp, Rel0),
  251.       !, do_rel(Rel0, ff(NTop, RTsTop, P), ff(NInp, RTsInp, P), Rel).
  252. % different priorities
  253. p(ff(NTop, TsTop, PTop), ff(NInp, TsInp, PInp), Pos,
  254.             gt(ff(NTop, RTsTop, PTop), ff(NInp, RTsInp, PInp))) :-
  255.       stronger(PTop, PInp), !,
  256.       restrict(TsInp, [fx, fy], RTsInp),
  257.       post_inpre(Pos, TsTop, RTsTop).
  258. p(ff(NTop, TsTop, PTop), ff(NInp, TsInp, PInp), Pos,
  259.           lseq(ff(NTop, RTsTop, PTop), ff(NInp, RTsInp, PInp))) :-
  260.       stronger(PInp, PTop), !,
  261.       restrict(TsTop, [xf, yf], RTsTop),
  262.       pre_inpost(Pos, TsInp, RTsInp).
  263.  
  264. p(_, dot, _, gt).
  265. p(bottom, _, _, lseq).
  266. % otherwise fail (p a r s e  fails, too)
  267.  
  268. vns_id_br(vns(_), _).
  269. vns_id_br(id(_), _).
  270. vns_id_br(br(LeftRight, _), LeftRight).
  271.  
  272. br_bar(br(LeftRight, _), LeftRight).
  273. br_bar(bar, _).
  274.  
  275. stronger(Prior1, Prior2) :- less(Prior1, Prior2).
  276.  
  277. pre_inpost(1, Types, RTypes) :-              % the functor must be prefix
  278.       restrict(Types, [xf, yf], A),
  279.       restrict(A, [xfy, yfx, xfx], RTypes).
  280. pre_inpost(2, Types, RTypes) :-              % the functor must not be prefix
  281.       restrict(Types, [fx, fy], RTypes).
  282.  
  283. post_inpre(1, Types, RTypes) :-              % the functor must be postfix
  284.       restrict(Types, [fx, fy], A),
  285.       restrict(A, [xfy, yfx, xfx], RTypes).
  286. post_inpre(2, Types, RTypes) :-              % the functor must not be postfix
  287.       restrict(Types, [xf, yf], RTypes).
  288.  
  289. % leave only those types that do not belong to RSet,
  290. % fail if this would leave no types at all (RSet contains
  291. % only binary types, or only unary types)
  292. restrict([T], RSet, [T]) :- !, not(member(T, RSet)).
  293. restrict([TBin, TUn], RSet, [TBin]) :- member(TUn, RSet), !.
  294. restrict([TBin, TUn], RSet, [TUn])  :- member(TBin, RSet), !.
  295. restrict(Types, _, Types).
  296.  
  297. % compute relation for two functors with equal priorities; four cases:
  298. %    both normal, Top mixed, Input mixed, both mixed
  299. res_confl([TTop], [TInp], Pos, [TTop], [TInp], Rel0) :-
  300.       !, ff_p(TTop, TInp, Pos, Rel0).
  301. res_confl([TTopBin, TTopUn], [TInp], Pos, RTsTop, [TInp], Rel0) :-
  302.       !, ff_p(TTopBin, TInp, Pos, RelB),
  303.       ff_p(TTopUn, TInp, Pos, RelU),
  304.       match_rels(RelB, RelU, Rel0, TTopBin, TTopUn, RTsTop).
  305. res_confl([TTop], [TInpBin, TInpUn], Pos, [TTop], RTsInp, Rel0) :-
  306.       !, ff_p(TTop, TInpBin, Pos, RelB),
  307.       ff_p(TTop, TInpUn, Pos, RelU),
  308.       match_rels(RelB, RelU, Rel0, TInpBin, TInpUn, RTsInp).
  309. res_confl([TTopBin, TTopUn], [TInpBin, TInpUn], Pos, RTsTop, RTsInp, Rel0) :-
  310.       ff_p(TTopBin, TInpBin, Pos, RelBB),
  311.       ff_p(TTopBin, TInpUn, Pos, RelBU),
  312.       ff_p(TTopUn, TInpBin, Pos, RelUB),
  313.       ff_p(TTopUn, TInpUn, Pos, RelUU),
  314.       res_mixed(RelBB, RelBU, RelUB, RelUU, Rel0,
  315.                 TTopBin, TTopUn, TInpBin, TInpUn, RTsTop, RTsInp), !.
  316.  
  317. do_rel(lseq, TopF, InpF, lseq(TopF, InpF)).
  318. do_rel(gt, TopF, InpF, gt(TopF, InpF)).
  319. % fail if Rel0 = err
  320.  
  321. match_rels(Rel, Rel, Rel, TBin, TUn, [TBin, TUn]) :- !.     % err included
  322. match_rels(err, Rel, Rel, _, TUn, [TUn]) :- !.
  323. match_rels(Rel, err, Rel, TBin, _, [TBin]) :- !.
  324. match_rels(_, _, err, TBin, TUn, [TBin, TUn]).
  325.  
  326. res_mixed(Rel0, Rel0, Rel0, Rel0, Rel0,
  327.             TTopBin, TTopUn, TInpBin, TInpUn,
  328.             [TTopBin, TTopUn], [TInpBin, TInpUn]).
  329. res_mixed(err, err, RelUB, RelUU, Rel0,
  330.             _, TTopUn, TInpBin, TInpUn, [TTopUn], RTsInp) :-
  331.       match_rels(RelUB, RelUU, Rel0, TInpBin, TInpUn, RTsInp).
  332. res_mixed(RelBB, RelBU, err, err, Rel0,
  333.             TTopBin, _, TInpBin, TInpUn, [TTopBin], RTsInp) :-
  334.       match_rels(RelBB, RelBU, Rel0, TInpBin, TInpUn, RTsInp).
  335. res_mixed(err, RelBU, err, RelUU, Rel0,
  336.             TTopBin, TTopUn, _, TInpUn, RTsTop, [TInpUn]) :-
  337.       match_rels(RelBU, RelUU, Rel0, TTopBin, TTopUn, RTsTop).
  338. res_mixed(RelBB, err, RelUB, err, Rel0,
  339.             TTopBin, TTopUn, TInpBin, _, RTsTop, [TInpBin]) :-
  340.       match_rels(RelBB, RelUB, Rel0, TTopBin, TTopUn, RTsTop).
  341. res_mixed(_, _, _, _, err, _, _, _, _, _, _).
  342.  
  343. % establish precedence relation for two (basic) types
  344. ff_p(TTop, TInp, Pos, lseq) :-
  345.       member(TTop, [xfy, fy]),      % right associative
  346.       ff_p_aux1(Pos, TInp), !.
  347. ff_p(TTop, TInp, Pos, gt) :-
  348.       member(TInp, [yfx, yf]),      % left associative
  349.       ff_p_aux2(Pos, TTop), !.
  350. ff_p(_, _, _, err).
  351.  
  352. ff_p_aux1(1, TInp) :- ispref(TInp).
  353. ff_p_aux1(2, TInp) :- member(TInp, [xfy, xf, xfx]).
  354.  
  355. ff_p_aux2(1, TTop) :- ispostf(TTop).
  356. ff_p_aux2(2, TTop) :- member(TTop, [yfx, fx, xfx]).
  357.  
  358. % ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  359. % - - - - - -         internal representation --> term         - - - - - -
  360. % ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  361.  
  362. maketerm(arg0(X), X) :- !.          % variable, atom, number, string
  363. maketerm(tr('()', RawTerm), T) :-
  364.       !, maketerm(RawTerm, T).
  365. maketerm(bar(RawList, RawTail), T) :-
  366.       !, maketerm(RawTail, Tail),
  367.       makelist(RawList, Tail, T).
  368. maketerm(tr('[]', RawList), T) :-
  369.       !, makelist(RawList, '[]', T).
  370. maketerm(tr('{}', RawArg), '{}'(Arg)) :-
  371.       !, maketerm(RawArg, Arg).
  372. maketerm(tr(Name, RawArgs), T) :-
  373.       !, makelist(RawArgs, '[]', Args),
  374.       =..(T, [Name | Args]).
  375. maketerm(tr2(Name, RawArg1, RawArg2), T) :-
  376.       !, maketerm(RawArg1, Arg1), maketerm(RawArg2, Arg2),
  377.       =..(T, [Name, Arg1, Arg2]).
  378. maketerm(tr1(Name, RawArg), T) :-
  379.       maketerm(RawArg, Arg), =..(T, [Name, Arg]).
  380.  
  381. % comma-term to dot-list-with-Tail
  382. makelist(tr2(',', RawArg, RawArgs), Tail, [Arg | Args]) :-
  383.       !, maketerm(RawArg, Arg), makelist(RawArgs, Tail, Args).
  384. makelist(RawArg, Tail, [Arg | Tail]) :- maketerm(RawArg, Arg).
  385.  
  386. % ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  387. % - - - - - -                   S C A N N E R                  - - - - - -
  388. % ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  389. % This scanner returns six kinds of tokens:
  390. %        vns(_)                  variables, numbers, strings
  391. %        id(Name)                atoms
  392. %        ff(Name, Types, Prior)  "fix" functors
  393. %        br(Which, Type)         brackets (left/right, '()' / '[]' / '{}')
  394. %        bar                     |  (in lists)
  395. %        dot                     . followed by a layout character
  396.  
  397. % - - - read a token and construct its internal form
  398. % the input is supposed to be positioned
  399. % over the first character of a token (or preceding "white space")
  400. gettoken(Token, Sym_tab) :-
  401.       skipbl, lastch(Startch), absorbtoken(Startch, Rawtoken), !,
  402.       maketoken(Rawtoken, Token, Sym_tab), !.
  403.  
  404. % - - - read in a suitable sequence of characters
  405. % a word, i.e. a regular alphanumeric identifier
  406. absorbtoken(Ch, id([Ch | Wordtail])) :-
  407.       wordstart(Ch), getword(Wordtail).
  408. % a variable
  409. absorbtoken(Ch, var([Ch | Tail])) :-
  410.       varstart(Ch), getword(Tail).
  411. % a solo character is a comma, a semicolon or an exclamation mark
  412. absorbtoken(Ch, id([Ch])) :- solochar(Ch), rch.
  413. % a bracket, i.e. ( ) [ ] { }
  414. absorbtoken(Ch, br(Wh, Type)) :-
  415.       bracket(Ch), bracket(Ch, Wh, Type), rch.
  416. absorbtoken('|', bar) :- rch.
  417. % a string in quotes or in double quotes
  418. absorbtoken('''', qid(Qname)) :-
  419.       rdch(Nextch), getstring('''', Nextch, Qname).
  420. absorbtoken('"', str(String)) :-
  421.       rdch(Nextch), getstring('"', Nextch, String).
  422. % a positive number
  423. absorbtoken(Ch, num([Ch | Digits])) :-
  424.       digit(Ch), getdigits(Digits).
  425. % a negative number or a dash (possibly starting a symbol, see below)
  426. absorbtoken(-, Rawtoken) :- rdch(Ch), num_or_sym(Ch, Rawtoken).
  427. absorbtoken(., Rawtoken) :- rdch(Ch), dot_or_sym(Ch, Rawtoken).
  428. % a symbol, built of . : - < = > + / * ? & $ @ # ^ \
  429. absorbtoken(Ch, id([Ch | Symbs])) :- symch(Ch), getsym(Symbs).
  430. % an embedded comment
  431. absorbtoken('%', Rawtoken) :-
  432.       skipcomment, lastch(Ch), absorbtoken(Ch, Rawtoken).
  433. % this shouldn't happen:
  434. absorbtoken(Ch, _) :- display(errinscan(Ch)), nl, fail.
  435.  
  436. num_or_sym(Ch, num([-, Ch | Digits])) :-
  437.       digit(Ch), getdigits(Digits).
  438. num_or_sym(Ch, id([-, Ch | Symbs])) :- symch(Ch), getsym(Symbs).
  439. num_or_sym(_, id([-])).
  440.  
  441. % layout characters precede ' ' in ASCII
  442. dot_or_sym(Ch, dot) :- @=<(Ch, ' ').         % no advance
  443. dot_or_sym(Ch, id([., Ch | Symbs])) :- symch(Ch), getsym(Symbs).
  444. dot_or_sym(_, id([.])).
  445.  
  446. skipcomment :- lastch(Ch), iseoln(Ch), skipbl, !.
  447. skipcomment :- rch, skipcomment.
  448.  
  449. % - - - auxiliary input procedures
  450. % read an alphanumeric identifier
  451. getword([Ch | Word]) :-
  452.       rdch(Ch), alphanum(Ch), !, getword(Word).
  453. getword([]).
  454.  
  455. % read a sequence of digits
  456. getdigits([Ch | Digits]) :-
  457.       rdch(Ch), digit(Ch), !, getdigits(Digits).
  458. getdigits([]).
  459.  
  460. % read a symbol
  461. getsym([Ch | Symbs]) :-
  462.       rdch(Ch), symch(Ch), !, getsym(Symbs).
  463. getsym([]).
  464.  
  465. % read a quoted id or string (Delim is either ' or ")
  466. getstring(Delim, Delim, Str) :-
  467.       !, rdch(Nextch), twodelims(Delim, Nextch, Str).
  468. getstring(Delim, Ch, [Ch | Str]) :-
  469.       rdch(Nextch), getstring(Delim, Nextch, Str).
  470. twodelims(Delim, Delim, [Delim | Str]) :-
  471.       !, rdch(Nextch), getstring(Delim, Nextch, Str).
  472. twodelims(_, _, []).    % close the list
  473.  
  474. % auxiliary tests
  475. wordstart(Ch) :- smalletter(Ch).
  476. varstart(Ch) :- bigletter(Ch).
  477. varstart('_').
  478. bracket('(', l, '()').           bracket(')', r, '()').
  479. bracket('[', l, '[]').           bracket(']', r, '[]').
  480. bracket('{', l, '{}').           bracket('}', r, '{}').
  481.  
  482. % transform a raw token into its final form
  483. maketoken(var(Namestring), vns(Ptr), Sym_tab) :-
  484.       makeptr(Namestring, Ptr, Sym_tab).
  485. maketoken(id(Namestring), Token, _) :-
  486.       pname(Name, Namestring), make_ff_or_id(Name, Token).
  487. maketoken(qid(Namestring), id(Name), _) :-
  488.       pname(Name, Namestring).
  489. maketoken(num([- | Digits]), vns(N), _) :-
  490.       pnamei(N1, Digits), sum(N, N1, 0).
  491. maketoken(num(Digits), vns(N), _) :- pnamei(N, Digits).
  492. maketoken(str(Chars), vns(Chars), _).
  493. maketoken(Token, Token, _).      % br(_,_) and bar and dot
  494.  
  495. % variables are kept in a symbol table (an open list)
  496. makeptr(['_'], _, _).      % no search - an anonymous variable
  497. makeptr(Nmstr, Ptr, Sym_tab) :- look_var(var(Nmstr, Ptr), Sym_tab).
  498.  
  499. % look-up
  500. look_var(Item, [Item | Sym_tab]).
  501. look_var(Item, [_ | Sym_tab]) :- look_var(Item, Sym_tab).
  502.  
  503. make_ff_or_id(Name, ff(Name, Types, Prior)) :-
  504.       'FF'(Name, Types, Prior).
  505. make_ff_or_id(Name, id(Name)).
  506.  
  507. % :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  508. % - - - - - -              GRAMMAR RULE PREPROCESSOR              - - - - - -
  509. % :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  510.  
  511. transl_rule(Left, Right, Clause) :-
  512.       two_ok(Left, Right),
  513.       isolate_lhs_t(Left, Nont, Lhs_t),
  514.       connect(Lhs_t, Outpar, Finalvar),
  515.       expand(Nont, Initvar, Outpar, Head),
  516.       makebody(Right, Initvar, Finalvar, Body, Alt_flag),
  517.       do_clause(Body, Head, Clause).
  518.  
  519. do_clause(true, Head, Head) :- !.
  520. do_clause(Body, Head, :-(Head, Body)).
  521.  
  522. % Lhs_t is a list (possibly empty) of lefthand side terminals
  523. isolate_lhs_t(','(Nont, Lhs_t), Nont, Lhs_t) :-
  524.       ';'(nonvarint(Nont), rulerror(varint)),
  525.       ';'(isclosedlist(Lhs_t), rulerror(ter)), !.
  526. isolate_lhs_t(Nont, Nont, []).
  527.  
  528. % fail if not a closed list
  529. isclosedlist(L) :- check(iscll(L)).
  530. iscll(L) :- var(L), !, fail.
  531. iscll([]).
  532. iscll([_ | L]) :- iscll(L).
  533.  
  534. % connect terminals to the nearest nonterminal's input parameter
  535. % (actually, "open" a closed list)
  536. connect([], Nextvar, Nextvar).
  537. connect([Tsym | Tsyms], [Tsym | Outpar], Nextvar) :-
  538.       connect(Tsyms, Outpar, Nextvar).
  539.  
  540. % - - - translate the righthand side (loop over alternatives)
  541. % in alternatives, each righthand side is preceded by a dummy
  542. % nonterminal, as defined by   ' dummy' --> [].    (since terminals
  543. % are appended to input parameters, the input parameter of a common
  544. % lefthand side must be a variable)
  545. makebody(';'(Alt, Alts), Initvar, Finalvar,
  546.          ';'(','(' dummy'(Initvar, Nextvar), Alt_b), Alt_bs), _) :-
  547.       !, two_ok(Alt, Alts),
  548.       makeright(Alt, Nextvar, Finalvar, Alt_b),
  549.       makebody(Alts, Initvar, Finalvar, Alt_bs, alt).
  550. makebody(Right, Initvar, Finalvar, Body, Alt_flag) :-
  551.       var(Alt_flag), !,       % only one alternative
  552.       makeright(Right, Initvar, Finalvar, Body).
  553. makebody(Right, Initvar, Finalvar,
  554.          ','(' dummy'(Initvar, Nextvar), Body), alt) :-
  555.       makeright(Right, Nextvar, Finalvar, Body).
  556.  
  557. % - - - translate one alternative
  558. makeright(','(Item, Items), Thispar, Finalvar, T_item_items) :-
  559.       !, two_ok(Item, Items),
  560.       transl_item(Item, Thispar, Nextvar, T_item),
  561.       makeright(Items, Nextvar, Finalvar, T_items),
  562.       combine(T_item, T_items, T_item_items).
  563. makeright(Item, Thispar, Finalvar, T_item) :-
  564.       transl_item(Item, Thispar, Finalvar, T_item).
  565.  
  566. combine(true, T_items, T_items) :- !.
  567. combine(T_item, true, T_item) :- !.
  568. combine(T_item, T_items, ','(T_item, T_items)).
  569.  
  570. % - - - translate one item (sure to be a functor-term)
  571. transl_item(Terminals, Thispar, Nextvar, true) :-
  572.       isclosedlist(Terminals),
  573.       !, connect(Terminals, Thispar, Nextvar).
  574. % conditions (the cut and others)
  575. transl_item(!, Thispar, Thispar, !) :- !.
  576. transl_item('{}'(Cond), Thispar, Thispar, call(Cond)) :- !.
  577. % bad list of terminals (missed the first clause)
  578. transl_item([_ | _], _, _, _) :- rulerror(ter).
  579. % a nested alternative
  580. transl_item(';'(X, Y), Thispar, Nextvar, Transl) :-
  581.       !, makebody(';'(X, Y), Thispar, Nextvar, Transl, _).
  582. % finally, a regular nonterminal
  583. transl_item(Nont, Thispar, Nextvar, Transl) :-
  584.       expand(Nont, Thispar, Nextvar, Transl).
  585.  
  586. % add input parameter and output parameter
  587. expand(Nont, In_par, Out_par, Call) :-
  588.       =..(Nont, [Fun | Args]),
  589.       =..(Call, [Fun, In_par, Out_par | Args]).
  590.  
  591. % - - - error handling
  592. two_ok(X, Y) :- nonvarint(X), nonvarint(Y), !.
  593. two_ok(_, _) :- rulerror(varint).
  594.  
  595. rulerror(Message) :-
  596.       nl, display('+++ Error in this rule: '), mes(Message), nl,
  597.       tagfail(transl_rule(_, _, _)).
  598. % diagnostics are only very brief (and not too informative ...)
  599. mes(varint) :- display('variable or integer item.').
  600. mes(ter) :- display('terminals not in a closed list.').
  601.  
  602. % - - - initiate grammar processing
  603. phrase(Nont, Terminals) :-
  604.       nonvarint(Nont), !,
  605.       expand(Nont, Terminals, [], Init_call),
  606.       call(Init_call).
  607. phrase(N, T) :- error(phrase(N, T)).
  608.  
  609. ' dummy'(X, X).
  610.  
  611.                          % ***************************
  612.                          % ***************************
  613.                          % ***    L I B R A R Y    ***
  614.                          % ***************************
  615.                          % ***************************
  616. % :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  617. % - - - - - -                 =..  (read as "univ")               - - - - - -
  618. % :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  619.  
  620. =..(X, Y) :- var(X), var(Y), !, error(=..(X, Y)).
  621. =..(Num, [Num]) :- integer(Num), !.
  622. =..(Term, [Fun | Args]) :-
  623.       setarity(Term, Args, N),
  624.       functor(Term, Fun, N),           % this works both ways
  625.       not(integer(Fun)),               % we dont't want e.g. 17(X)
  626.       setargs(Term, Args, 0, N).       % this works both ways, too
  627.  
  628. setarity(Term, Args, N) :- var(Term), !, length(Args, N).
  629.          % notice that bad Args give an error in  l e n g t h
  630. setarity(_, _, _).      % Arity will be set by  f u n c t o r  in =..
  631.  
  632. % both numeric parameters are given,
  633. % the loop stops when the third reaches the fourth
  634. % (works both ways because  a r g  does)
  635. setargs(_, [], N, N) :- !.
  636. setargs(Term, [Arg | Args], K, N) :-
  637.       sum(K, 1, K1), arg(K1, Term, Arg),
  638.       setargs(Term, Args, K1, N).
  639.  
  640. % find the length of a closed list; error if not closed
  641. length(List, N) :- length(List, 0, N).
  642.  
  643. % this is a tail-recursive formulation of length
  644. length(L, _, _) :- var(L), !, error(length(L, _)).
  645. length([], N, N) :- !.
  646. length([_ | List], K, N) :-
  647.       !, sum(K, 1, K1), length(List, K1, N).
  648. length(Bizarre, _, _) :- error(length(Bizarre, _)).
  649.  
  650. % bind every variable to a distinct 'V'(N)
  651. numbervars('V'(N), N, NextN) :- !, sum(N, 1, NextN).
  652. numbervars('V'(_), N, N) :- !.
  653. numbervars(X, N, N) :- integer(X), !.
  654. numbervars(X, N, NextN) :- numbervars(X, 1, N, NextN).
  655.  
  656. numbervars(X, K, N, NextN) :-
  657.       arg(K, X, A), !, numbervars(A, N, MidN),
  658.       sum(K, 1, K1), numbervars(X, K1, MidN, NextN).
  659. numbervars(_, _, N, N).
  660.  
  661. % :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  662. % - - - - - -           PREDEFINED "FIX" FUNCTORS ETC.            - - - - - -
  663. % :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  664.  
  665. % op has been defined as a system routine, together with 'FF' and delop
  666.  
  667. :- op(1000, xfy, ',').  % ordered according to probable frequency
  668. :- op(1200, xfx, :- ).
  669. :- op(1200, fx,  :- ).
  670. :- op(1100, xfy, ';').
  671. :- op( 900, fy,  not).
  672. :- op( 700, xfx, =  ).
  673. :- op( 700, xfx, is ).
  674. :- op(1200, xfx, -->).
  675. :- op( 500, yfx, +  ).
  676. :- op( 500, fx,  +  ).
  677. :- op( 500, yfx, -  ).
  678. :- op( 500, fx,  -  ).
  679. :- op( 400, yfx, *  ).
  680. :- op( 400, yfx, /  ).
  681. :- op( 300, xfx, mod).
  682. :- op( 700, xfx, <  ).
  683. :- op( 700, xfx, =< ).
  684. :- op( 700, xfx, >  ).
  685. :- op( 700, xfx, >= ).
  686. :- op( 700, xfx, =:=).
  687. :- op( 700, xfx, =\=).
  688. :- op( 700, xfx, @< ).
  689. :- op( 700, xfx, @=<).
  690. :- op( 700, xfx, @> ).
  691. :- op( 700, xfx, @>=).
  692. :- op( 700, xfx, =..).
  693. :- op( 700, xfx, == ).
  694. :- op( 700, xfx, \==).
  695.  
  696. % test for binary and instantiate Assoc
  697. binary(yfy, a(_)).         % arbitrarily associative
  698. binary(xfy, a(r)).         % right associative
  699. binary(yfx, a(l)).         % left associative
  700. binary(xfx, na(_)).        % non-associative
  701. % test for unary, instantiate Kind and Assoc
  702. unary(fy, pre, a(r)).      % right associative
  703. unary(fx, pre, na(r)).     % right non-associative
  704. unary(yf, post, a(l)).     % left associative
  705. unary(xf, post, na(l)).    % left non-associative
  706.  
  707. % :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  708. % - - - - - -          EVALUATE AN ARITHMETIC EXPRESSION          - - - - - -
  709. % :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  710.  
  711. is(N, N) :- integer(N), !.
  712. is(Val, +(A, B)) :-
  713.       !, is(Av, A), is(Bv, B), sum(Av, Bv, Val).
  714. is(Val, -(A, B)) :-
  715.       !, is(Av, A), is(Bv, B), sum(Bv, Val, Av).
  716. is(Val, *(A, B)) :-
  717.       !, is(Av, A), is(Bv, B), prod(Av, Bv, 0, Val).
  718. is(Val, /(A, B)) :-
  719.       !, is(Av, A), is(Bv, B), prod(Bv, Val, _, Av).
  720. is(Val, mod(A, B)) :-
  721.       !, is(Av, A), is(Bv, B), prod(Bv, _, Val, Av).
  722. is(Val, +(A)) :- !, is(Val, A).
  723. is(Val, -(A)) :- !, is(Av, A), sum(Val, Av, 0).
  724. is(N, [N]) :- integer(N).
  725. % otherwise  f a i l
  726.  
  727. % - - - - - - EVALUATE AN ARITHMETIC RELATION - - - - - -
  728. =:=(X, Y) :- is(Val, X), is(Val, Y).
  729. <(X, Y)   :- is(Xv, X), is(Yv, Y), less(Xv, Yv).
  730. =<(X, Y)  :- is(Xv, X), is(Yv, Y), not(less(Yv, Xv)).
  731. >(X, Y)   :- is(Xv, X), is(Yv, Y), less(Yv, Xv).
  732. >=(X, Y)  :- is(Xv, X), is(Yv, Y), not(less(Xv, Yv)).
  733. =\=(X, Y) :- not(=:=(X, Y)).
  734.  
  735. % :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  736. % - - - - - -               PERFECT EQUALITY OF TERMS             - - - - - -
  737. % :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  738.  
  739. ==(T1, T2) :- var(T1), var(T2), !, eqvar(T1, T2).
  740. ==(T1, T2) :- check(==?(T1, T2)).
  741.  
  742. \==(T1, T2) :- not(==?(T1, T2)).
  743.  
  744. ==?(T1, T2) :-
  745.       integer(T1), integer(T2), !, =(T1, T2).
  746. ==?(T1, T2) :-
  747.       nonvarint(T1), nonvarint(T2),
  748.       functor(T1, Fun, Arity), functor(T2, Fun, Arity),
  749.       equalargs(T1, T2, 1).
  750.  
  751. equalargs(T1, T2, Argnumber) :-
  752.       arg(Argnumber, T1, Arg1), arg(Argnumber, T2, Arg2),
  753.             % arg fails given too large a number
  754.       !, ==(Arg1, Arg2), sum(Argnumber, 1, Nextnumber),
  755.       equalargs(T1, T2, Nextnumber).
  756. equalargs(_, _, _).
  757.  
  758. % :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  759. % - - - - - -      assert, asserta, assertz, retract, clause      - - - - - -
  760. % :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  761. % - - - add a clause (using built-in assert/3)
  762. assert(Cl) :- asserta(Cl).
  763. asserta(Cl) :-
  764.       nonvarint(Cl), convert(Cl, Head, Body), !,
  765.       assert(Head, Body, 0).
  766. asserta(Cl) :- error(asserta(Cl)).
  767.  
  768. assertz(Cl) :-
  769.       nonvarint(Cl), convert(Cl, Head, Body), !,
  770.       assert(Head, Body, 32767).       % i.e. MAXINT in this implementation
  771. assertz(Cl) :- error(assertz(Cl)).
  772.  
  773. % convert the external form of a Body into a dotted list
  774. convert(:-(Head, B), Head, Body) :- conv_body(B, Body).
  775. convert(Unit_cl, Unit_cl, []).
  776.  
  777. % this procedure works both ways
  778. conv_body(B, [call(B)]) :- var(B), !.
  779. conv_body(true, []).
  780. conv_body(B, Body) :- conv_b(B, Body).
  781.  
  782. conv_b(B, [Body]) :- var(B), !, conv_call(B, Body).
  783. conv_b(','(C, B), [Call | Body]) :-
  784.       !, conv_call(C, Call), conv_b(B, Body).
  785. conv_b(Call, [Call]).      % sure to be no variable
  786.  
  787. % interpreter can process variable calls only within  c a l l
  788. conv_call(C, call(C)) :- var(C), !.
  789. conv_call(C, C).
  790.  
  791. % - - - remove a clause (this procedure is backtrackable)
  792. retract(Cl) :-
  793.       nonvarint(Cl), convert(Cl, Head, Body), !,
  794.       functor(Head, Fun, Arity), remcls(Fun, Arity, 1, Head, Body).
  795. retract(Cl) :- error(retract(Cl)).
  796.  
  797. % ultimate failure if N too big (retract/3 fails)
  798. remcls(Fun, Arity, N, Head, Body) :-
  799.    clause(Fun, Arity, N, N_head, N_body),
  800.    remcls(Fun, Arity, N, N_head, Head, N_body, Body).
  801.  
  802. remcls(Fun, Arity, N, Head, Head, Body, Body) :-
  803.    retract(Fun, Arity, N).
  804. % user's backtracking resumes  r e t r a c t  here
  805. % (after removing the Nth clause the next becomes Nth)
  806. remcls(Fun, Arity, N, N_head, Head, N_body, Body) :-
  807.       check(=(N_head, Head)), check(=(N_body, Body)),
  808.       !, remcls(Fun, Arity, N, Head, Body).
  809. remcls(Fun, Arity, N, _, Head, _, Body) :-
  810.       sum(N, 1, N1), remcls(Fun, Arity, N1, Head, Body).
  811.  
  812. % - - - generate nondeterministically all clauses whose head
  813. %       and body match the parameters of  c l a u s e
  814. clause(Head, Body) :-
  815.       nonvarint(Head), !, functor(Head, Fun, Arity),
  816.       gencls(Fun, Arity, 1, Head, Body).
  817. clause(Head, Body) :- error(clause(Head, Body)).
  818.  
  819. % generate: ultimate failure if N too big (clause/5 fails)
  820. gencls(Fun, Arity, N, Head, Body) :-
  821.       clause(Fun, Arity, N, N_head, N_body),
  822.       gencls(Fun, Arity, N, N_head, Head, N_body, Body).
  823.  
  824. % fail if N_head does not match Head,
  825. % or if N_body converted does not match Body
  826. gencls(_, _, _, N_head, N_head, N_body, Body) :-
  827.       conv_body(Body, N_body).
  828. % user's backtracking resumes  c l a u s e  here
  829. gencls(Fun, Arity, N, _, Head, _, Body) :-
  830.       sum(N, 1, N1), gencls(Fun, Arity, N1, Head, Body).
  831.  
  832. % :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  833. % - - - - - -                       L I S T I N G                 - - - - - -
  834. % :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  835. % list procedures determined by the parameter (listing/1)
  836. %                    or all user's procedures (listing/0)
  837. listing :-
  838.    proc(Head), listproc(Head), nl, fail.
  839. listing.    % catch the final fail from  p r o c
  840.  
  841. listing(Fun) :- atom(Fun), !, listbyname(Fun).
  842. listing(/(Fun, Arity)) :-
  843.       atom(Fun), integer(Arity), =<(0, Arity), !,
  844.       functor(Head, Fun, Arity), listproc(Head).
  845. listing(L) :-
  846.       isclosedlist(L), listseveral(L), !.
  847. listing(X) :- error(listing(X)).
  848.       % isclosedlist - cf. grammar rule preprocessor
  849.  
  850. listseveral([]).
  851. listseveral([Item | Items]) :-
  852.       listing(Item), listseveral(Items).
  853.  
  854. % all procedures with this name
  855. listbyname(Fun) :-
  856.       proc(Head), functor(Head, Fun, _),
  857.       listproc(Head), nl, fail.
  858. listbyname(_).    % succeed
  859.  
  860. % one procedure
  861. listproc(Head) :-
  862.       clause(Head, Body),
  863.       writeclause(Head, Body), wch(.), nl, fail.
  864. listproc(_).      % succeed
  865.  
  866. writeclause(Head, Body) :-
  867.       not(var(Body)), =(Body, true), !, writeq(Head).
  868. writeclause(Head, Body) :- writeq(:-(Head, Body)).
  869.  
  870. % :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  871. % - - - - - -                        W R I T E                    - - - - - -
  872. % :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  873.  
  874. write(Term) :- side_effects(outterm(Term, noq)).
  875.  
  876. % writeq encloses in quotes all identifiers except words,
  877. % symbols and solochars (not coinciding with "fix" functors)
  878. writeq(Term) :- side_effects(outterm(Term, q)).
  879.  
  880. writetext([Ch | Chs]) :- !, wch(Ch), writetext(Chs).
  881. writetext([]).
  882.  
  883. outterm(T, Q) :- numbervars(T, 1, _), outt(T, fd(_,_), Q).
  884.  
  885. % the real job is done here
  886. outt(X, _, _) :- var(X), !, wch('_').
  887.                   % applies only to anonymous variables read in by
  888.                   % the "kernel" reader
  889. outt('V'(N), _, _) :- integer(N), !, wch('X'), display(N).
  890.                   % C A U T I O N :  outt is unable to write 'V'(Integer)
  891. outt(Term, _, _) :- integer(Term), display(Term), !.
  892. % the second parameter specifies a context for "fix" functors:
  893. % the nearest external functor and Term's position
  894. % (to the left or to the right of the external functor)
  895. outt(Term, Context, Q) :-
  896.       =..(Term, [Name | Args]),
  897.       outfun(Name, Args, Context, Q).
  898.  
  899. % - - - output a functor-term
  900. %   -   as a "fix" term
  901. outfun(Name, Args, Context, Q) :-
  902.       isfix(Name, Args, This_ff, Kind), !,
  903.       outff(Kind, This_ff, [Name | Args], Context, Q).
  904. %   -   as a list
  905. outfun(., [Larg, Rarg], _, Q) :-
  906.       !, outlist([Larg | Rarg], Q).
  907. %   -   as a normal functor-term
  908. outfun(Name, Args, _, Q) :-
  909.       outname(Name, Q), outargs(Args, Q).
  910.  
  911. % isfix constructs a pair  ff(Prior, Associativity), and
  912. % 'in' or 'pre' or 'post' (fails if not a "fix" functor)
  913. isfix(Name, [_, _], ff(Prior, Assoc), in) :-
  914.       'FF'(Name, Types, Prior), mk_bin(Types, Assoc).
  915. isfix(Name, [_], ff(Prior, Assoc), Kind) :-
  916.       'FF'(Name, Types, Prior), mk_un(Types, Kind, Assoc).
  917.  
  918. % Bintype (if any) is before Untype (if any)
  919. mk_bin([Bintype | _], Assoc) :- binary(Bintype, Assoc).
  920. mk_un([Untype], Kind, Assoc) :- unary(Untype, Kind, Assoc).
  921. mk_un([_, Untype], Kind, Assoc) :- unary(Untype, Kind, Assoc).
  922. % tests - see  o p
  923.  
  924. % - - - output a "fix" term (this outff has 5 parameters)
  925. outff(Kind, This_ff, NameArgs, Context, Q) :-
  926.       agree(This_ff, Context), !,
  927.       outff(Kind, This_ff, NameArgs, Q).
  928. outff(Kind, This_ff, NameArgs, _, Q) :-
  929.       wch('('), outff(Kind, This_ff, NameArgs, Q), wch(')').
  930.  
  931. % agree helps avoid (some) unnecessary brackets around the term
  932. agree(_, fd(Ext_ff, _)) :- var(Ext_ff).
  933. agree(ff(Prior1, _), fd(ff(Prior2, _), _)) :-
  934.       stronger(Prior1, Prior2).        % cf. the parser
  935. agree(ff(Prior, a(Dir)), fd(ff(Prior, a(Dir)), Dir)).
  936.  
  937. % output the functor and the arguments (this outff has 4 parameters)
  938. outff(in, This_ff, [Name, Larg, Rarg], Q) :-
  939.       outt(Larg, fd(This_ff, l), Q),
  940.       outfn(Name, ' '), outt(Rarg, fd(This_ff, r), Q).
  941. outff(pre, This_ff, [Name, Arg], Q) :-
  942.       outfn(Name, ' '), outt(Arg, fd(This_ff, r), Q).
  943. outff(post, This_ff, [Name, Arg], Q) :-
  944.       outt(Arg, fd(This_ff, l), Q), outfn(Name, ' ').
  945.  
  946. % output functor's name enclosed in Encl
  947. % if Encl is not a space, double ocurrences of Encl  w i t h i n  Name
  948. outfn(Name, ' ') :- !, wch(' '), display(Name), wch(' ').
  949. outfn(Name, Encl) :- wch(Encl), pname(Name, NmString),
  950.       outfn1(NmString, Encl), wch(Encl).
  951.  
  952. outfn1([], _) :- !.
  953. outfn1([E | T], E) :- !, wch(E), wch(E), outfn1(T, E).
  954. outfn1([C | T], E) :- wch(C), outfn1(T, E).
  955.  
  956. % - - - print a name (in quotes, if necessary)
  957. outname(Name, noq) :- !, display(Name).
  958. outname(Name, q) :-
  959.       'FF'(Name, _, _), !, outfn(Name, '''').
  960. outname(Name, q) :-
  961.       pname(Name, Namestring),
  962.       check(noq(Namestring)), !, display(Name).
  963. outname(Name, q) :- outfn(Name, '''').
  964.  
  965. noq([Ch | String]) :- wordstart(Ch), isword(String).
  966. noq([Ch]) :- solochar(Ch).
  967. noq(['[', ']']).
  968. noq([Ch | String]) :- symch(Ch), issym(String).
  969.  
  970. isword([]).
  971. isword([Ch | String]) :- alphanum(Ch), isword(String).
  972. issym([]).
  973. issym([Ch | String]) :- symch(Ch), issym(String).
  974.  
  975. % - - - output a list of arguments (cf. outfun)
  976. outargs([], _) :- !.
  977. outargs(Args, Q) :-
  978.       fake(Context), wch('('), outargs(Args, Context, Q), wch(')').
  979.  
  980. outargs([Last], Context, Q) :- !, outt(Last, Context, Q).
  981. outargs([Arg | Args], Context, Q) :-
  982.       outt(Arg, Context, Q), display(', '), outargs(Args, Context, Q).
  983.  
  984. % commas are used to delimit list items, so we must bracket commas
  985. % w i t h i n  items (it's a trick: we depend on ',' having
  986. %   the priority 1000 and being associative)
  987. fake(fd(ff(1000, na(_)), _)).
  988.  
  989. % - - - output a list in square brackets (cf. outfun - the main
  990. %   functor is the dot, and the list cannot be empty)
  991. outlist([First | Tail], Q) :-
  992.          fake(Context), wch('['), outt(First, Context, Q),
  993.          outlist(Tail, Context, Q), wch(']').
  994.  
  995. outlist([], _, _) :- !.
  996. outlist([Item | Items], Context, Q) :-
  997.       !, display(', '), outt(Item, Context, Q),
  998.       outlist(Items, Context, Q).
  999. % the bar and the closing item (still bracketed if it contains commas)
  1000. outlist(Closing, Context, Q) :-
  1001.       display(' | '), outt(Closing, Context, Q).
  1002.  
  1003.                       % *********************************
  1004.                       % *********************************
  1005.                       % ***    T R A N S L A T O R    ***
  1006.                       % *********************************
  1007.                       % *********************************
  1008.  
  1009. % read a program upto  "end."  and translate it into "kernel" form
  1010. translate(Infile, Outfile) :-
  1011.       see(Infile), tell(Outfile),
  1012.       nl, repeat,
  1013.          read(Clause, OrgST), put(Clause, OrgST), nl, =(Clause, end), !,
  1014.       seen, told, see(user), tell(user).
  1015.  
  1016. % - - - produce and output the translation of one clause
  1017. put(:-(Head, Body), OrgST) :-
  1018.       !, puthead(Head, Sym_tab), putbody(Body, Sym_tab),
  1019.       put_varnames(OrgST, Sym_tab, 0).
  1020. put(-->(Left, Right), OrgST) :-
  1021.       !, tag(transl_rule(Left, Right, :-(Head, Body))),
  1022.       puthead(Head, Sym_tab), putbody(Body, Sym_tab),
  1023.       put_varnames(OrgST, Sym_tab, 0).
  1024. put(:-(Goal), OrgST) :-
  1025.       !, putbody(Goal, Sym_tab), wch(#), nl,
  1026.       put_varnames(OrgST, Sym_tab, 0),
  1027.       once(Goal).    % a failure here wouldn't matter (cf. translate)
  1028. put(end, _) :- !, putbody(seen, _), wch(#), nl.
  1029.       % this is for security
  1030. put('e r r', _) :- !.
  1031. put(Unitclause, OrgST) :- puthead(Unitclause, Sym_tab), putbody(true, _),
  1032.       put_varnames(OrgST, Sym_tab, 0).
  1033.  
  1034. % - - - put a head call (it must be a functor-term)
  1035. puthead(Head, Sym_tab) :-
  1036.       nonvarint(Head), !, putterm(Head, Sym_tab).
  1037. puthead(Head, _) :- transl_err(Head).
  1038.  
  1039. % - - - put a list of calls and [] at the end
  1040. putbody(Body, Sym_tab) :-
  1041.       punct(:), conv_body(Body, B), !, putbody_c(B, Sym_tab).
  1042.                % see assert etc. for  c o n v _ b o d y
  1043.  
  1044. putbody_c([], _) :- !, display([]).
  1045. putbody_c([Term | Terms], Sym_tab) :-
  1046.       not(integer(Term)), !, putterm(Term, Sym_tab),
  1047.       punct(.), putbody_c(Terms, Sym_tab).
  1048. putbody_c([Term | _], _) :- transl_err(Term).
  1049.  
  1050. punct(Ch) :- wch(' '), wch(Ch), nl, display('   ').
  1051.  
  1052. % - - - put a term (with infix dots, and canonical otherwise)
  1053. putterm(Term, Sym_tab) :-
  1054.       var(Term), !, lookup(Term, Sym_tab, -1, N),
  1055.       wch(:), display(N).
  1056. putterm(Term, _) :- integer(Term), !, display(Term).
  1057. putterm([Head | Tail], Sym_tab) :-
  1058.       !, putterm_inlist(Head, Sym_tab),
  1059.       display(' . '), putterm(Tail, Sym_tab).
  1060. putterm(Term, Sym_tab) :-
  1061.       =..(Term, [Name | Args]), outfn(Name, ''''),    % cf.  w r i t e
  1062.       putargs(Args, Sym_tab).
  1063.  
  1064. % Sym_tab is an open list of pairs  vn(Variable, Number)
  1065. % (this formulation helps avoid too many additions)
  1066. lookup(V, S_t_end, PreviousN, N) :-
  1067.       var(S_t_end), !, sum(PreviousN, 1, N),
  1068.       =(S_t_end, [vn(V, N) | New_S_t_end]).
  1069. lookup(V, [vn(CurrV, CurrN) | _], _, CurrN) :-
  1070.       eqvar(V, CurrV), !.
  1071. lookup(V, [vn(_, CurrN) | S_t_tail], _, N) :-
  1072.       lookup(V, S_t_tail, CurrN, N).
  1073.  
  1074. % arguments - nothing, or a list of terms in parentheses
  1075. putargs([], _) :- !.
  1076. putargs(Args, Sym_tab) :-
  1077.       wch('('), putarglist(Args, Sym_tab), wch(')').
  1078.  
  1079. putarglist([Arg], Sym_tab) :- !, putterm(Arg, Sym_tab).
  1080. putarglist([Arg | Args], Sym_tab) :-
  1081.       putterm(Arg, Sym_tab), display(', '),
  1082.       putarglist(Args, Sym_tab).
  1083.  
  1084. % - - - a list within a list must be enclosed in parentheses
  1085. putterm_inlist(Term, Sym_tab) :-
  1086.       nonvarint(Term), =(Term, [_ | _]), !,
  1087.       wch('('), putterm(Term, Sym_tab), wch(')').
  1088. putterm_inlist(Term, Sym_tab) :- putterm(Term, Sym_tab).
  1089.  
  1090. % - - - error handling (only one error is discovered by translate)
  1091. transl_err(X) :-
  1092.       nl, display('+++ Bad head or call: '), display(X), nl, fail.
  1093.  
  1094. % - - - output names of source variables paired with numbers
  1095. put_varnames(_, EndOfST, _) :- var(EndOfST), !.
  1096. put_varnames(OrgST, [vn(Inst, Num) | RestOfST], Count) :-
  1097.       find_varname(Inst, OrgST, Num, Name), nextline(Count),
  1098.       wch(' '), display(Num), wch(' '), writetext(Name), wch(','),
  1099.       sum(Count, 1, NextCount), put_varnames(OrgST, RestOfST, NextCount).
  1100.  
  1101. find_varname(_, EndOrgST, Num, ['X' | Digits]) :-
  1102.       var(EndOrgST), !, pnamei(Num, Digits).
  1103. find_varname(Inst, [var(Name, Inst1) | _ ], _, Name) :-
  1104.       eqvar(Inst, Inst1), !.
  1105. find_varname(Inst, [_ | RestOrgST], Num, Name) :-
  1106.       find_varname(Inst, RestOrgST, Num, Name).
  1107.  
  1108. nextline(N) :- prod(6, _, 0, N), !, nl, display('   %%').
  1109. nextline(_).
  1110.  
  1111. %::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  1112. %- - - - - - - - - protect / unprotect all of the library - - - - - - - - - -
  1113. %::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  1114. protect :-
  1115.       proc(Proc), functor(Proc, Name, Arity), protect(Name, Arity), fail.
  1116. protect :- display('All predicates protected.'), nl.
  1117.  
  1118. unprotect :-
  1119.       proc(Proc), functor(Proc, Name, Arity), unprotect(Name, Arity), fail.
  1120. unprotect :- display('All predicates un-protected.'), nl.
  1121.  
  1122. % ok, monitor loaded - protect it (the system will start up the 'ear' goal)
  1123.  
  1124. :- grf_mse_hide, txt_mode, protect, seen.
  1125.  
  1126.